#pragma once

#include <string>
#include <map>
#include "SmartPtr.h"

using std::string;
using std::map;

class CvarSystem;

class Cvar
{
	union {
		int _ivalue;
		float _fvalue;
		bool _bvalue;
		char *_svalue;
	};

	bool _set;

private:
	Cvar(int value) { _ivalue = value; }
	Cvar(float value) { _fvalue = value; }
	Cvar(bool value) { _bvalue = value; }
	Cvar(char* value) { _svalue = value; }

	friend class CvarSystem;

public:
	int getValueI() const { return _ivalue; }
	float getValueF() const { return _fvalue; }
	bool getValueB() const { return _bvalue; }
	char* getValueS() const { return _svalue; }

	void setValue(int value) { _ivalue = value; }
	void setValue(float value) { _fvalue = value; }
	void setValue(bool value) { _bvalue = value; }
	void setValue(char* value) { _svalue = value; }
};

typedef SmartPtr<Cvar> CvarPtr;

class CvarSystem
{
private:
	CvarSystem() {};

public:
	static CvarSystem& getInstance();

	static CvarPtr getCvar(const string& name, bool createIfNotExists = false);

	static CvarPtr addCvar(const string& name, int defaultValue = 0);
	static CvarPtr addCvar(const string& name, float defaultValue = 0.0f);
	static CvarPtr addCvar(const string& name, bool defaultValue = false);
	static CvarPtr addCvar(const string& name, char* defaultValue = "");

private:
	template <typename T>
	static CvarPtr addCvarInternal(const string& name, T defaultValue, bool set);

	typedef map<string, SmartPtr<Cvar> > CvarMap;
	typedef SmartPtr<CvarSystem> CvarSysPtr;

	static CvarSysPtr _instance;
	static CvarMap _cvars;
};